%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  版权归Du Wenliang所有。                                       %%
%%  此作品根据知识共享署名-非商业性使用-相同方式分享4.0国际许可协议授权。 %%
%%  要查看此许可证，请访问                           %%
%%  http://creativecommons.org/licenses/by-nc-sa/4.0/.              %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand{\commonfolder}{../../common-files}

\input{\commonfolder/header}
\input{\commonfolder/copyright}

\newcommand{\firewallFigs}{./Figs}
\lhead{\bfseries SEED Labs -- 防火墙规避实验}

\begin{document}



\begin{center}
{\LARGE 防火墙规避实验：使用VPN绕过防火墙}
\end{center}


\seedlabcopyright{2018}

\newcounter{task}
\setcounter{task}{1}
\newcommand{\tasks} {\bf {\noindent (\arabic{task})} \addtocounter{task}{1} \,}


% *******************************************
% SECTION
% ******************************************* 
\section{概述}

组织、互联网服务提供商（ISP）和国家通常会阻止其内部用户访问某些外部网站。这被称为出口过滤。
例如，为了防止工作时间的分心，许多公司会在他们的出口防火墙上设置规则以屏蔽社交网络站点，
这样员工就无法从公司的网络中访问这些网站。出于政治原因，许多国家在ISP层面设置了出口过滤，屏蔽其人民对特定外国网站的访问。
不幸的是，这些防火墙可以很容易地被绕过，并且帮助用户绕过防火墙的服务/产品在网上广泛可用。
最常用的绕过出口防火墙的技术是虚拟私人网络（VPN）。
特别是这项技术被智能手机用户广泛使用，他们在受出口过滤影响的情况下会使用它；
有许多适用于Android、iOS及其他平台的VPN应用程序可以帮助用户绕过出口防火墙。

本实验的学习目标是让学生看到
如何在实际中应用VPN以及如何使用VPN来绕过出口防火墙。
我们将在本次实验中实现一个非常简单的VPN，并利用它来绕过防火墙。典型的VPN依赖于两种技术：IP隧道和加密。
隧道技术是最基本的，可以帮助绕过防火墙；而加密技术则是为了保护通过VPN隧道传输的内容。
为简化问题，我们仅关注于建立隧道的过程，并不对传输的流量进行加密处理。
我们有一个独立的
VPN实验室涵盖隧道和加密两方面内容。如果读者感兴趣的话，可以完成我们的VPN实验以学习如何构建完整的VPN系统。
在本次实验中，我们将仅关注使用VPN隧道绕过防火墙的方法。
本实验涵盖以下主题：

\begin{itemize}[noitemsep]
\item 防火墙
\item VPN
\end{itemize}

\paragraph{阅读材料和视频。}
有关防火墙、防火墙规避技术以及VPN的详细内容可以在以下几个位置找到

\begin{itemize}
\item SEED Book中的第17章和第19章，\seedbook
\item SEED Lecture中的第8节和第9节，\seedisvideo
\end{itemize}

\paragraph{实验环境。}\seedenvironmentB

% *******************************************
% SECTION
% ******************************************* 
\section{实验任务}




% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{任务1：虚拟机设置}

我们需要两台机器，一台在防火墙内，另一台在防火墙外。
目标是帮助位于防火墙内的那台机器访问被防火墙屏蔽的外部网站。
我们使用两个虚拟机VM1和VM2来模拟这两台机器。VM1与VM2通过互联网连接，
这可能需要超过两台虚拟机。为简化起见，我们将用一个局域网（LAN）来仿真互联网连接。
实际上，我们可以简单地使用NAT Network适配器将VM1和VM2连接到一个局域网中。
图~\ref{vpn_firewall:fig:labsetup}展示了实验环境设置。

\begin{figure}[htb]
  \begin{center}
    \includegraphics[width=0.9\textwidth]{\firewallFigs/Host2Gateway.pdf}
  \end{center}
  \caption{实验室环境设置}
  \label{vpn_firewall:fig:labsetup}
\end{figure}




% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{任务2：设置防火墙}

在本任务中，您将在VM1上设置一个防火墙以阻止对特定目标网站的访问。
请确保目标网站的IP地址是固定的或在一个固定范围内；否则，
可能无法完全屏蔽该站点。有关如何屏蔽网站的具体操作，请参阅防火墙实验室。

在现实世界中，防火墙应该运行在单独的一台机器上，并且不是在VM1上。为减少实验中使用的虚拟机数量，
我们把防火墙放在了VM1上。
在VM1上设置防火墙需要超级用户权限。
同样，设置VPN隧道也需要超级用户权限。有人可能会立即说，如果我们已经有超级用户的权限，
为什么不能直接关闭VM1上的防火墙。这是一个很好的论点，但是请注意，我们将防火墙放在VM1上
仅仅是因为我们不想在实验环境中创建另一台虚拟机。
因此，尽管您在VM1上有超级用户权限，
但不允许使用该权限重新配置防火墙。
您必须使用VPN来绕过它。

与将防火墙放置在外置机器相比，在VM1上设置防火墙确实有一些小问题需要处理。
当我们设置防火墙以阻止数据包时，我们需要确保不会阻止到达用于VPN的虚拟接口的数据包，
否则我们的VPN就无法接收到这些数据包。因此我们不能在路由之前或在虚拟接口上设置防火墙规则。
只需要在VM1的实际网络接口上设置规则即可，这样就不会影响到流向虚拟接口的数据包了。
以下命令可以阻止所有流量到达\texttt{93.184.216.0/24} 网络（\texttt{example.com}）：

\begin{lstlisting}
$ sudo iptables -A OUTPUT -o enp0s3 -d 93.184.216.0/24 -j DROP
\end{lstlisting}

请确定一个您想要屏蔽的网站，设置防火墙，并验证您的防火墙工作正常且目标IP地址不再可访问。
在实验报告中提供屏幕截图。


% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{任务3：使用VPN绕过防火墙}

使用VPN来绕过防火墙的想法如图~\ref{vpn_firewall:fig:bypassing}所示。
我们在VM1（VPN客户端虚拟机）和VM2（VPN服务器虚拟机）之间建立一个VPN隧道。当VM1上的用户尝试访问被屏蔽的网站时，
数据包不会直接通过其网络适配器传输，因为会被拦截阻止。相反，来自VM1的数据包将被路由到VPN隧道，并到达VM2。
一旦到达那里，VM2将把这些数据包转发至最终目的地。
当回复数据包返回时，它会回到VM2，然后由VM2重定向这些数据包通过隧道，
最后把数据包传回给VM1。这就是如何使用VPN帮助VM1绕过防火墙的。

\begin{figure}[htb]
\begin{center}
\includegraphics[width=1.0\textwidth]{\firewallFigs/BypassingFirewall.pdf}
\end{center}
\caption{使用VPN绕过防火墙}
\label{vpn_firewall:fig:bypassing}
\end{figure}

我们创建了一个样本的VPN程序，包括客户端程序（\texttt{vpnclient}）和服务器程序（\texttt{vpnserver}），它们都可以从该实验室网站下载。
这个简单的VPN程序仅在客户端和服务器之间建立一个隧道；
它不对隧道中的流量进行加密。此程序的具体细节可以在SEED书籍的VPN章节中找到。

\begin{figure}[htb]
\begin{center}
\includegraphics[width=0.9\textwidth]{\firewallFigs/ClientServerTunnel.pdf}
\end{center}
\caption{客户端和服务器端程序}
\label{vpn_firewall:fig:client_server}
\end{figure}

\texttt{vpnclient} 和 \texttt{vpnserver} 程序是VPN隧道的两端。它们通过图~\ref{vpn_firewall:fig:client_server}中所示的套接字使用TCP或UDP进行通信。
在我们的示例代码中，为简化起见我们选择使用UDP。客户端和服务器之间虚线表示的是VPN隧道路径。
VPN客户端和服务器程序通过TUN接口连接到主机系统，并通过它完成以下两项工作：
（1）获取来自主系统的IP包以便可以通过隧道传输；
（2）从隧道获取IP包并将其转发给主机系统，该系统会将数据包发送到最终的目的地。
下面的步骤描述了如何使用 \texttt{vpnclient} 和 \texttt{vpnserver} 程序创建一个VPN隧道。

\paragraph{步骤1：运行VPN服务器}
我们首先在Server VM上运行VPN服务器程序 \texttt{vpnserver}。运行此程序后，系统中会显示一个新的虚拟TUN网络接口（我们可以使用“ifconfig -a”命令查看；大多数情况下接口名称为tun0，但也可以是tunX）。
此时该新接口尚未配置好，我们需要通过分配IP地址来对其进行配置。
我们通常为这个接口指定\texttt{192.168.53.1}的IP地址，不过您也可以使用其他IP地址。

运行以下命令。第一个命令将启动服务器程序，
第二个命令则会向tun0接口分配一个IP地址并激活它。需要特别注意的是，第一个命令将会阻塞且等待连接，
因此我们需要在另一个窗口中执行第二个命令。

\begin{lstlisting}
$ sudo ./vpnserver

请在另一个窗口运行以下命令：
$ sudo ifconfig tun0 192.168.53.1/24 up
\end{lstlisting}

如果没有特别配置，计算机通常仅作为主机工作而不会充当网关。
VPN服务器需要将数据包转发到其他目的地，因此它需要像网关一样运行。
为了使计算机像网关那样行为我们需要启用IP转发。可以通过以下命令启用IP转发：

\begin{lstlisting}
$ sudo sysctl net.ipv4.ip_forward=1
\end{lstlisting}

\paragraph{步骤2：运行VPN客户端}
我们现在在Client VM上运行VPN客户端程序。
我们在此机器上执行如下命令（第一个命令将连接到运行在{\tt 10.0.2.8}的VPN服务器程序）。
此命令也将阻塞，因此我们需要在一个不同的窗口中配置由VPN客户端创建的tun0接口，
并给tun0接口分配IP地址\texttt{192.168.53.5}（您可以选择其他IP地址）。

在VPN客户端虚拟机上：
\begin{lstlisting}
$ sudo ./vpnclient 10.0.2.8
\end{lstlisting}

请在一个不同的窗口中运行以下命令：
\begin{lstlisting}
$ sudo ifconfig tun0 192.168.53.5/24 up
\end{lstlisting}

\paragraph{步骤3：客户端和服务器虚拟机的路由设置}
经过上述两步后，隧道已建立。
但在我们可以使用隧道之前，
需要在客户端和服务器机器上进行相应的路由设置以使目的流量通过隧道传输。 
我们可以用route命令添加一个路由条目。
下面是一个示例，说明如何将\texttt{10.20.30.0/24}-bound包路由到接口eth0。

\begin{lstlisting}
$ sudo route add -net 10.20.30.0/24 eth0
\end{lstlisting}

为了在Client VM上绕过防火墙，您需要设置相应的路由条目，
将指向被屏蔽站点的流量通过VPN传输。
您需要考虑需添加哪些路由条目以实现绕开防火墙的目的。

\paragraph{步骤4：服务器虚拟机上的NAT配置}
当最终目标发送数据包返回给用户时，该数据包首先会传送到VPN Server（想想为什么并在报告中写下您的答案）。
返回的数据包先到达VPN Server的NAT适配器（因为从Server VM发出去的所有数据包的源IP地址都已更改成NAT的外部IP地址，
基本上是主机计算机上的IP地址）。通常，NAT会将目的IP地址更改为原始数据包中的IP地址
（例如在我们的例子中为\texttt{192.168.53.5}），并将数据包传回拥有该IP地址的实体。
不幸的是我们遇到了一个问题。

在NAT发送数据包之前，它需要知道拥有\texttt{192.168.53.5} IP地址的机器的MAC地址，
因此它会发出一个ARP请求。我们的私有网络是虚拟的，此IP地址属于VPN客户端上的tun0接口。
所以 \texttt{192.168.53.5} 不会收到ARP请求（即使它确实收到了也不会有任何用处）。
NAT将会丢弃该数据包，因为收件人不存在。

实际接收者应该是服务器虚拟机VM，尽管它本身并不拥有\texttt{192.168.53.5}这个IP地址。如果我们可以将NAT配置为网关，
我们可以要求NAT把发往 \texttt{192.168.53.5} 的数据包转发给VPN Server，最终通过隧道传输到VPN客户端。
然而我们在VirtualBox中还没有找到如何将NAT配置为网关的方法，因此我们找到了两个变通的解决方案。一种想法是“欺骗”NAT，
使其相信 \texttt{192.168.53.5} 的MAC地址就是服务器虚拟机VM的MAC地址，这样数据包就能通过NAT传递给服务器。
我们可以使用ARP缓存投毒在NAT上实现这一点，基本就是在向NAT发送之前告知它\texttt{192.168.53.5}的MAC地址。

绕过NAT限制的一个更好解决方案是在Server VM上创建另一个NAT，
这样从服务器虚拟机发出的所有数据包都将以该虚拟机的IP地址作为源IP地址。
为了访问互联网，这些数据包将通过VirtualBox提供的另一个NAT，但由于源IP是服务器虚拟机，
因此第二个NAT可以毫无问题地转发来自Internet返回的数据包给服务器虚拟机。使用此解决方案，
我们不再需要使用ARP缓存投毒来“欺骗”NAT了。以下命令可以在Server VM上启用NAT（在您的情况下，NAT网络适配器的名称可能不是enp0s3；
您只需要找到自己VM上的真实名称）：

\begin{lstlisting}
$ sudo iptables -t nat -A POSTROUTING -j MASQUERADE -o enp0s3
\end{lstlisting}

\paragraph{演示}
如果您正确地完成了上述步骤，那么应该能够绕过防火墙了。您需要展示从Client VM 通过VPN可以访问被屏蔽的网站。
您的解决方案不仅应适用于Web流量，还应对所有其他类型的流量有效。例如，
如果被屏蔽机器运行了一个telnet服务器，则您可以使用Client VM上的telnet连接到该被屏蔽服务器。

在实验报告中，请使用Wireshark或其他网络分析工具来捕获并展示您绕过防火墙的数据传输路径，证明其确实经过了所构建的VPN通道而非其他途径。


% *******************************************
% SECTION
% ******************************************* 
\section{提交要求}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\input{\commonfolder/submission}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\end{document}